/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package unmsm.fisi.tesis.si;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;

import unmsm.fisi.tesis.dao.FitnessDAO;
import unmsm.fisi.tesis.dao.GeneracionDAO;
import unmsm.fisi.tesis.dao.PoblacionDAO;
import unmsm.fisi.tesis.entidad.Configuracion;
import unmsm.fisi.tesis.entidad.Cromosoma;
import unmsm.fisi.tesis.entidad.CromosomaFinal;
import unmsm.fisi.tesis.entidad.Poblacion;

/**
 * 
 * @author Jhon
 */
public class AlgoritmoGenetico implements Serializable {

	/**
	 * 
	 */
	private static final long serialVersionUID = 7407069277398936810L;
	private Poblacion poblacion;
	private Operadores operadores;
	private Seleccion seleccion;
	private Cromosoma cromosomaSeleccionada_1;
	private Cromosoma cromosomaSeleccionada_2;

	private StringBuilder seguimiento;

	public void ejecutar(Configuracion configuracion) {

		this.setSeguimiento(new StringBuilder());
		this.poblacion = new Poblacion();
		this.seleccion = new Seleccion();
		this.seleccion.setSeguimiento(this.getSeguimiento());
		this.seleccion.setFitnnesMayores(new Vector());
		this.seleccion.getFitnnesMayores().addElement("0".toString());
		this.operadores = new Operadores();

		int contadorHijos = 0, contadorGeneraciones, contadorIteraciones = 0;
		int poblacionInicial;
		double[] frecuenciasAcumuladas;
		List<Cromosoma> ListaCromosomasHijos;
		
		Carga cargaInformacion = new Carga();
		if (configuracion.getMetodo().compareTo("algoritmo") == 0) {
			
			limpiarInformacionBaseDatos();
			poblacion = cargaInformacion.generarPoblacionInicial(configuracion,seguimiento);

		} else {

			poblacion = obtenerUltimaPoblacionDesdeBaseDeDatos();
		
		}
		
		contadorGeneraciones = Constantes.ULTIMO_NUMERO_GENERACION_FINAL;
		configuracion.setNumGeneraciones(Constantes.ULTIMO_NUMERO_GENERACION_FINAL + configuracion.getNumGeneraciones());
		

		// seleccion.evaluarValorCromosoma(configuracion,
		// poblacion.getListaCromosomas());

		while (contadorGeneraciones <= configuracion.getNumGeneraciones()) {

			this.getSeguimiento().append("<br>");
			pintarMensajes("*************** GENERACION # "+ contadorGeneraciones + "*******************");

			contadorHijos = 0; contadorIteraciones = 1;

			seleccion.evaluarValorCromosoma(configuracion,	poblacion.getListaCromosomas());
			poblacionInicial = poblacion.getTamanioPoblacion();
			
			frecuenciasAcumuladas = seleccion.calcularfrecuenciasAcumuladas(configuracion, this.poblacion.getListaCromosomas());
			
			/*if (contadorGeneraciones % 50 == 0 && contadorGeneraciones != 0) {
				Poblacion poblacionAyuda = cargaInformacion.generarPoblacionInicial(configuracion, seguimiento);
				seleccion.evaluarValorCromosoma(configuracion,	poblacionAyuda.getListaCromosomas());
				this.poblacion.agregarHijosAPoblacion(poblacionAyuda.getListaCromosomas());
			}*/
			
			do {
				pintarMensajes("---- ITERACION #" + contadorIteraciones);

				double random_r = (double) (Math.random());

				if (random_r <= configuracion.getProbabilidadCrossover_x()) {

					pintarMensajes("(" + random_r + " >= Realiza Crossover)");
					cromosomaSeleccionada_1 = seleccion.metodoRuleta(configuracion,this.poblacion.getListaCromosomas(),frecuenciasAcumuladas);
					cromosomaSeleccionada_2 =seleccion.metodoRuleta(configuracion,this.poblacion.getListaCromosomas(),frecuenciasAcumuladas);
					
					pintarMensajes("      Padre 1  y Padre 2");// mostrarCromosomaSeleccionados(cromosomaSeleccionada_2.getGenes());

					if(contadorGeneraciones %10 == 0 || contadorGeneraciones % 5 == 0 || contadorGeneraciones % 3 == 0 || contadorGeneraciones % 7 == 0)
						ListaCromosomasHijos = operadores.crossover2(cromosomaSeleccionada_1, cromosomaSeleccionada_2, this.getSeguimiento(), contadorGeneraciones);
					 else
						 ListaCromosomasHijos = operadores.crossover(cromosomaSeleccionada_1, cromosomaSeleccionada_2, this.getSeguimiento(), contadorGeneraciones);
					
					seleccion.evaluarValorCromosoma(configuracion,	ListaCromosomasHijos);
					this.poblacion.agregarHijos(ListaCromosomasHijos);

					contadorHijos = contadorHijos + ListaCromosomasHijos.size();

					pintarMensajes("      Hijo Cruzado 1    y    Hijo Cruzado 2");// mostrarCromosomaSeleccionados(cromosomasHijos[1].getGenes());

					ListaCromosomasHijos = null;
					cromosomaSeleccionada_1 = null;
					cromosomaSeleccionada_2 = null;

				}
				if (random_r <= configuracion.getProbabilidadMutacion_y()) {

					cromosomaSeleccionada_1 = seleccion.metodoRuleta(configuracion,this.poblacion.getListaCromosomas(), frecuenciasAcumuladas);
				
					ListaCromosomasHijos = operadores.mutacion(cromosomaSeleccionada_1, this.getSeguimiento(),contadorGeneraciones);
					seleccion.evaluarValorCromosoma(configuracion,	ListaCromosomasHijos);
					this.poblacion.agregarHijoMutado(ListaCromosomasHijos);
					contadorHijos = contadorHijos + ListaCromosomasHijos.size();

					pintarMensajes("(" + random_r + ">= Realiza Mutacion)");
					pintarMensajes("      Padre a Mutar");// mostrarCromosomaSeleccionados(cromosomaSeleccionada_1.getGenes());
					pintarMensajes("      Hijo Mutado");// mostrarCromosomaSeleccionados(cromosomaMutado.getGenes());

					ListaCromosomasHijos = null;
					cromosomaSeleccionada_1 = null;
				}

				for (Cromosoma cromosoma : poblacion.getListaCromosomas()) {
					cromosoma.setFlagSeleccion(false);
				}

				contadorIteraciones++;

			} while (contadorHijos <= configuracion.getNumeroPoblacion());//

			this.poblacion.agregarHijosAPoblacion(this.poblacion.getListaHijosCromosomas());

			guardarInformacionDeGeneracion(contadorGeneraciones,contadorIteraciones, poblacionInicial,configuracion.getCodigoConfiguracion());

			Poblacion nueva_poblacion = new Poblacion();
			List<Cromosoma> listaNuevasCromosomas = seleccion.seleccionarNuevaPoblacion(poblacion, configuracion, contadorGeneraciones);
			nueva_poblacion.setListaCromosomas(listaNuevasCromosomas);
			this.poblacion = null;
			this.poblacion = nueva_poblacion;
			this.poblacion.setTamanioPoblacion(nueva_poblacion.getListaCromosomas().size());
	

			contadorGeneraciones++;
		}

		guardarUltimaPoblacion(poblacion, contadorGeneraciones-1);
		guardarDatosDeAlgoritmo();

	}

	public void pintarMensajes(String mensaje) {

		System.out.println(mensaje);
		this.getSeguimiento().append(mensaje);
		this.getSeguimiento().append("<br>");
	}

	public void guardarInformacionDeGeneracion(int numGeneracion, int iteraciones, int poblacionInicial, int codigoConfiguracion) {
		String detalle = "Geracion #" + numGeneracion;
		PoblacionDAO.asignarGeneracionYPoblacion(numGeneracion, detalle,	iteraciones, poblacionInicial, this.poblacion.getTamanioPoblacion(), codigoConfiguracion);
	}

	public void guardarUltimaPoblacion(Poblacion poblacion, int numGeneracion) {

		String cadena;
		for (Cromosoma individuo : poblacion.getListaCromosomas()) {
			cadena = convertitMatrizACadena(individuo.getConocimiento());
			PoblacionDAO.guardarCromosomasFinalesxGeneracion(cadena, numGeneracion, Constantes.NUMERO_CROMOSOMAS -1 , individuo);

		}
	}
	
	public Poblacion obtenerUltimaPoblacionDesdeBaseDeDatos(){
		
		List<CromosomaFinal> ListaCromosomaFinal= PoblacionDAO.obtenerUltimaPoblacionDesdeBaseDeDatos();
		return crearPobacionDesdeCromosomasFinales(ListaCromosomaFinal);
		
	}
	public void guardarDatosDeAlgoritmo(){
		
		GeneracionDAO.guardarResumenDeAlgoritmo();
		FitnessDAO.guardarNacimientoDeFitnes();
		FitnessDAO.guardarCantidadCromosomasEnFitnnes();
	}
	
	
	public Poblacion crearPobacionDesdeCromosomasFinales(List<CromosomaFinal> ListaCromosomaFinal){
		
		Poblacion poblacion= new Poblacion();
		Cromosoma crom;
		List<Cromosoma> listaCromosomas= new ArrayList<Cromosoma>();
		
		for (CromosomaFinal cromosomafinal : ListaCromosomaFinal) {
			
			crom = new Cromosoma();
			int [][]conocimiento = convertitCadenaAMatriz(cromosomafinal.getNumerofila(), cromosomafinal.getNumerocolumna(),
					cromosomafinal.getConocimiento());
			crom.setConocimiento(conocimiento);
			crom.setNumeroCromosoma(cromosomafinal.getNumeroCromosoma());
			Constantes.NUMERO_CROMOSOMAS= cromosomafinal.getUltimoCromosoma() +1 ;
			Constantes.ULTIMO_NUMERO_GENERACION_FINAL = cromosomafinal.getNumeroGeneracion() + 1;
			listaCromosomas.add(crom);
		}
		
		
		poblacion.setListaCromosomas(listaCromosomas);
		poblacion.setTamanioPoblacion(listaCromosomas.size());
		
		return poblacion;
	} 

	public String convertitMatrizACadena(int conocimiento[][]) {

		StringBuffer cadena = new StringBuffer();

		for (int x = 0; x < conocimiento.length; x++) {

			for (int y = 0; y < conocimiento[0].length; y++) {

				cadena.append(conocimiento[x][y]);
				// cadena.append(",");

			}
			cadena.append("-");

		}

		String cadena2 = cadena.toString().substring(0,
				cadena.toString().length() - 2);

		return cadena2;
	}

	public int[][] convertitCadenaAMatriz(int fila, int columna, String data) {

		int matraiz[][] = new int[fila][columna];

		String[] datosFila = data.toString().split("-");

		for (int x = 0; x < datosFila.length; x++) {
			String cadena = datosFila[x];
			char[] datosColumn = cadena.toCharArray();

			for (int y = 0; y < datosColumn.length; y++) {
				char val = datosColumn[y];
				matraiz[x][y] = Integer.parseInt(Character.toString(val));
			}

		}
		return matraiz;
	}

	public void limpiarInformacionBaseDatos() {

		FitnessDAO objFitnes = new FitnessDAO();
		objFitnes.eliminarGeneracionCromosomaPoblacionFitnes();
	}

	public boolean condicion() {
		return true;
	}

	public void mostrarCromosomaSeleccionados(int conocimiento[][]) {

		// System.out.println("Conocimiento #"+(i+1)+"\n");
		for (int j1 = 0; j1 < conocimiento.length; j1++) {

			for (int j2 = 0; j2 < conocimiento[j1].length; j2++) {
				System.out.print(conocimiento[j1][j2] + ",");
				this.getSeguimiento().append(conocimiento[j1][j2] + ",");
			}
			System.out.print("\n");
			this.getSeguimiento().append("<br>");

		}

		System.out.print("\n");
		System.out.print("\n");

		this.getSeguimiento().append("<br>");
		this.getSeguimiento().append("<br>");

	}

	public StringBuilder getSeguimiento() {
		return seguimiento;
	}

	public void setSeguimiento(StringBuilder seguimiento) {
		this.seguimiento = seguimiento;
	}

	public Seleccion getSeleccion() {
		return seleccion;
	}

	public void setSeleccion(Seleccion seleccion) {
		this.seleccion = seleccion;
	}

}
